-- local string = string
-- setfenv (1, getfenv(2))
--[[for k,v in pairs(getfenv(3)) do print(k,v) end]]
module (...,
 function (_M)
  local mt = {}
  for k,v in pairs(_G) do
    if type(v)=='function' then mt[k]=v end
  end
  mt['string']=string
  mt['table']=table
	mt['io'] = {}
	mt['io']['popen']=io.popen -- !!! WARNING !!!
  setmetatable(_M,{__index = mt})
 end
 )

-- remove leading/trailing spaces from a string
function trim (s)
  return string.gsub (s, "^%s*(.-)%s*$", "%1")
end -- trim()

function capitalize (s)
  return string.upper (string.sub (s, 1, 1)) .. 
          string.lower (string.sub (s, 2))
end --  capitalize()

-- for k,v in pairs(getmetatable(_M).__index) do print(k,v) end

-- ----------------------------------------------------------
-- serializer
-- See "Programming In Lua" chapter 12.1.2.
-- Also see forum thread:
--   http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4960
-- ----------------------------------------------------------
function basicSerialize (o)
  if type(o) == "number" or type(o) == "boolean" then
    return tostring(o)
  else   -- assume it is a string
    return string.format("%q", o)
  end
end -- basicSerialize 

--
-- Lua keywords might look OK to not be quoted as keys but must be.
-- So, we make a list of them.
--

lua_reserved_words = {}

for _, v in pairs ({
    "and", "break", "do", "else", "elseif", "end", "false", 
    "for", "function", "if", "in", "local", "nil", "not", "or", 
    "repeat", "return", "then", "true", "until", "while"
            }) do lua_reserved_words [v] = true end

-- ----------------------------------------------------------
-- save one variable (calls itself recursively)
-- 
-- Modified on 23 October 2005 to better handle keys (like table keys)
-- ----------------------------------------------------------
function save (name, value, out, indent, saved)
  saved = saved or {}       -- initial value
  indent = indent or 0      -- start indenting at zero cols
  local iname = string.rep (" ", indent) .. name -- indented name

  -- numbers, strings, and booleans can be simply serialized

  if type(value) == "number" or 
     type(value) == "string" or
     type(value) == "boolean" then
    table.insert (out, iname .. " = " .. basicSerialize(value))

  -- tables need to be constructed, unless we have already done it

  elseif type(value) == "table" then
    if saved[value] then    -- value already saved?
      table.insert (out, iname .. " = " .. saved[value])  -- use its previous name
    else

  -- remember we have created this table so we don't do it twice

      saved[value] = name   -- save name for next time

  -- make the table constructor, and recurse to save its contents

      table.insert (out, iname .. " = {}")   -- create a new table
      local k, v
      for k, v in pairs (value) do      -- save its fields
        local fieldname 

        -- if key is a Lua variable name which is not a reserved word
        -- we can express it as tablename.keyname

        if type (k) == "string"
           and string.find (k, "^[_%a][_%a%d]*$") 
           and not lua_reserved_words [k] then
          fieldname = string.format("%s.%s", name, k)

        -- if key is a table itself, and we know its name then we can use that
        --  eg. tablename [ tablekeyname ]

        elseif type (k) == "table" and saved[k] then
          fieldname = string.format("%s[%s]", name, saved [k]) 

        -- if key is an unknown table, we have to raise an error as we cannot
        -- deduce its name
 
        elseif type (k) == "table" then
          error ("Key table entry " .. tostring (k) .. 
                 " in table " .. name .. " is not known")

        -- if key is a number or a boolean it can simply go in brackets,
        -- like this:  tablename [5] or tablename [true]

        elseif type (k) == "number" or type (k) == "boolean" then
          fieldname = string.format("%s[%s]", name, tostring (k))

        -- now key should be a string, otherwise an error
 
        elseif type (k) ~= "string" then
          error ("Cannot serialize table keys of type '" .. type (k) ..
                 "' in table " .. name)

        -- if key is a non-variable name (eg. "++") then we have to put it
        -- in brackets and quote it, like this:  tablename ["keyname"]

        else
          fieldname  = string.format("%s[%s]", name,
                                        basicSerialize(k))  
        end

        -- now we have finally worked out a suitable name for the key,
        -- recurse to save the value associated with it

        save(fieldname, v, out, indent + 2, saved) 
      end
    end

  -- cannot serialize things like functions, threads

  else
    error("Cannot save a " .. type(value))
  end
end  -- save 

-- ----------------------------------------------------------
-- Serialize a variable or nested set of tables:
-- ----------------------------------------------------------

--[[

  Example of use:

  SetVariable ("mobs", serialize ("mobs"))  --> serialize mobs table
  loadstring (GetVariable ("mobs")) ()  --> restore mobs table 

  If you need to serialize two tables where subsequent ones refer to earlier ones
  you can supply your own "saved tables" variable, like this:

    t = {}
    result = serialize ("mobs", nil, t)
    result = result .. "\n" .. serialize ("quests", nil, t)

  In this example the serializing of "quests" also knows about the "mobs" table
  and will use references to it where necessary.  

  You can also supply the actual variable if the variable to be serialized does
  not exist in the global namespace (for instance, if the variable is a local 
  variable to a function). eg.

    do
      local myvar = { 1, 2, 8, 9 }
      print (serialize ("myvar", myvar))
    end

  In this example, without supplying the location of "myvar" the serialize would fail
  because it would not be found in the _G namespace.

--]]

function serialize (what, v, saved)
  v = v or _G [what]  -- default to "what" in global namespace

  assert (type (what) == "string", 
          "1st argument to serialize should be the *name* of a variable")
  
  assert (v, "Variable '" .. what .. "' does not exist")

  assert (type (saved) == "table" or type (saved) == "nil", 
          "3rd argument to serialize should be a table or nil")

  local out = {}  -- output to this table
  save (what, v, out, nil, saved)   -- do serialization
  table.insert (out, "")  -- final entry to force out newline
  return table.concat (out, "\r\n")  -- turn into a string
end -- serialize



--lsdir implementation from SciTE
--VERY cuted
--works perhaps only on windows
--[[function scite_Files(mask,opt)
  local f,path,path2
  local tmpfile = '\\temp1'
  opt = opt or ''
 
	mask = gsub(mask,'/','\\')
	_,_,path = find(mask,'(.*\\)')
	_,_,path2 = find(path,'^[\.]*[\\]?(.*)') --removing '.'+'\' or '..'+'\' in path
	--[DEBUG][BEGIN]
	--print("mask = "..mask)
	--print("path = "..path)
	--if path ~= path2 then
	-- print("path2 = "..path2)
	--end 
	--[DEBUG][END]
	local cmd = 'dir /b'..opt..' "'..mask..'" > '..tmpfile
	os.execute(cmd)
	f = io.open(tmpfile)
  
  local files = {}
  if not f then return files end
  
  --local relpath --relative path to file
  
  for line in f:lines() do
		append(files,line)  
  end
  
  --[DEBUG][BEGIN]
  --print('files:',files)
  -- for k,v in pairs(files) do print(k,v) end
  --[DEBUG][END]
	
  f:close()
  return files
end]]

--print('now come lsdir')
--[[function lsdir(dir)
 --print('we are in lsdir('..dir..')!')
 local path = dir
 if (string.sub(dir,-1) ~= '\\') and (string.sub(dir,-1) ~= '/')
 then
    path = path..'\\'
 end
 --return scite_Files(path..'*','/A-D /S')
 return scite_Files(path..'*')
end
-- end of lsdir implementation]]

function lsonedir(path, files)
local path = (path and path:gsub('/','\\'):gsub('^(%.*%\\*)','..\\')) or "..\\" --i start basically from "../" with the file operations in the server.
path = path:gsub('^(..\\.+)(\\?)$','%1\\') --add \ at the end
local outputpath = path:sub(3):gsub('\\','/') -- to show

	local f = assert(io.popen ('dir /b/a-d '..path)) --only files
	local files = files or {}
	-- local files = {}
	for line in f:lines() do
		files[#files+1]=outputpath..line
	end
	f:close()

	local f = assert(io.popen ('dir /b/ad '..path))
	for line in f:lines() do
		--[[files[#files+1]=]] lsonedir(path..line, files) --outputpath..line..'    [D]'
	end
	f:close()

	return files
end --lsonedir()

-- local path = '..\\server'
-- local t = lsonedir(path)
-- for k,v in pairs(t) do print(k,v) end
-- print(path:gsub('/','\\'):gsub('^(%.*%\\*)','..\\'))
-- print(path:gsub('^(%.*%\\*)','..\\'))
-- print(serialize('files',t))